package com.lzc.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.lzc.mapper.ArticleDetailMapper;
import com.lzc.mapper.ArticleMapper;
import com.lzc.mapper.ErrorKeyMapper;
import com.lzc.mapper.ImgLibraryMapper;
import com.lzc.pojo.dto.ArticleDto;
import com.lzc.pojo.entity.Article;
import com.lzc.pojo.entity.ArticleDetail;
import com.lzc.pojo.entity.ErrorKey;
import com.lzc.pojo.entity.ImgLibrary;
import com.lzc.pojo.vo.ArticlePublishVo;
import com.lzc.pojo.vo.Result;
import com.lzc.service.ArticleService;
import com.lzc.util.ThreadLocalUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver;
import org.thymeleaf.templateresolver.ITemplateResolver;

import java.io.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Service
public class ArticleServiceImpl implements ArticleService {

    @Autowired
    private ArticleMapper articleMapper;

    @Autowired
    private ImgLibraryMapper imgLibraryMapper;

    @Autowired
    private ArticleDetailMapper articleDetailMapper;

    @Autowired
    private ErrorKeyMapper errorKeyMapper;

    @Autowired
    private TemplateEngine templateEngine;

    // 文章磁盘路径地址
    @Value("${file.articleDiskPathPrefix}")
    private String articleDiskPathPrefix;

    @Value("${api.articlePageUrl}")
    private String articlePageUrl;

    /**
     * 发布文章
     * @param articlePublishVo 文章信息VO
     * @return 200
     */
    @Override
    @Transactional
    public Result publishArticle(ArticlePublishVo articlePublishVo) {
        // 主题不能为空
        if (StrUtil.isBlank(articlePublishVo.getTitle())){
            return Result.FILE("主题不能为空！！");
        }
        // 图片至少要有一张
        if (CollectionUtil.isEmpty(articlePublishVo.getImages())){
            return Result.FILE("图片至少要有一张！！");
        }
        // 包装article数据
        Article article = new Article();
        article.setTitle(articlePublishVo.getTitle());
        article.setState(-1); // 待审核
        article.setUid(ThreadLocalUtil.getUid()); // 当前用户
        // 获取第一张图片地址做为封面
        ImgLibrary coverImg = imgLibraryMapper.selectOne(new LambdaQueryWrapper<ImgLibrary>().eq(
                ImgLibrary::getId, articlePublishVo.getImages().get(0)
        ));
        if (coverImg == null){
            return Result.FILE("发布失败，请稍后重试!");
        }
        article.setCoverImg(coverImg.getSrc());
        article.setCreateTime(LocalDateTime.now());
        // 存入数据库
        articleMapper.insert(article);
        // 包装articleDetail内容
        ArticleDetail articleDetail = new ArticleDetail();
        articleDetail.setId(article.getId());
        articleDetail.setContext(articlePublishVo.getContext());
        // list -> string
        String images = JSONUtil.toJsonStr(articlePublishVo.getImages());
        articleDetail.setImages(images);
        articleDetailMapper.insert(articleDetail);

        // TODO异步审核
        articleReview(article.getId());
        return Result.OK(null);
    }

    /**
     * 异步审核文章
     * @param id 文章id
     */
    private void articleReview(Long id){
        // 更新文章状态
        articleMapper.update(new LambdaUpdateWrapper<Article>().eq(Article::getId,id)
                .set(Article::getState,0));
        // 获取文章详细内容
        ArticleDetail articleDetail = articleDetailMapper.selectOne(new LambdaQueryWrapper<ArticleDetail>()
                .eq(ArticleDetail::getId, id));

        // 审核内容
        String context = articleDetail.getContext();

        // 进行审核
        // 获取错误违禁词集合
        List<ErrorKey> errorKeys = errorKeyMapper.selectList(null);
        for (ErrorKey errorKey : errorKeys) {
            // 文章审核
            if (context.contains(errorKey.getText())){
                // 审核失败
                articleMapper.update(new LambdaUpdateWrapper<Article>().eq(Article::getId,id)
                        .set(Article::getState,2));
                return;
            }
        }
        // TODO 图片审核

        // 审核成功，生成url
        String articleUrl = createArticleDetailPage(articleDetail);
        // 存入数据库
        articleMapper.update(new LambdaUpdateWrapper<Article>().eq(Article::getId,id)
                .set(Article::getState,1)
                .set(Article::getArticleUrl,articleUrl)
                .set(Article::getCreateTime,LocalDateTime.now())
        );
    }

    /**
     * 生成文章详情页面
     * @param articleDetail 文章详情
     * @return 页面url
     */
    private String createArticleDetailPage(ArticleDetail articleDetail){
        String format = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd-hh-mm-ss-"));
        // 生成文件名
        String articleName = format + articleDetail.getId()+".html";
        // 创建文件
        File file = new File(articleDiskPathPrefix + articleName);
        if (!file.exists()){
            try {
                file.createNewFile();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        // 获取文章标题和图片集合
        // 1. 获取文章标题
        Article article = articleMapper.selectById(articleDetail.getId());
        // 2. 获取图片集合
        String imagesStr = articleDetail.getImages();
        List<Long> imageIds = JSONUtil.parseArray(imagesStr).toList(Long.class);
        List<ImgLibrary> imgLibraries = imgLibraryMapper.selectBatchIds(imageIds);
        List<String> images = imgLibraries.stream().map(ImgLibrary::getSrc).collect(Collectors.toList());
        // 创建模型数据
        Context context = new Context();
        context.setVariable("title",article.getTitle());
        context.setVariable("context",articleDetail.getContext());
        context.setVariable("images",images);
        context.setVariable("articleDetail",articleDetail);

        // 获取输出流
        try(Writer writer = new PrintWriter(file)) {
            // 生成页面
            createTemplatePage("article",context,writer);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        return articlePageUrl+articleName;
    }

    /**
     * 创建页面
     * @param templateName 模板名称
     * @param context 模型内容
     * @param writer 输出流
     */
    private void createTemplatePage(String templateName, Context context, Writer writer){
        Set<ITemplateResolver> templateResolvers = templateEngine.getTemplateResolvers();

        if (CollectionUtil.isEmpty(templateResolvers)){
            SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
            resolver.setPrefix("classpath:/templates/");
            resolver.setSuffix(".html");
            templateEngine.setTemplateResolver(resolver);
        }

        templateEngine.process(templateName,context,writer);
    }

    /**
     * 文章最近发布列表
     * @return list
     */
    @Override
    public Result findArticleNewList() {
        List<ArticleDto> articleDtos = articleMapper.findArticleNewList();
        return Result.OK(articleDtos);
    }

    /**
     * 获取当前用户发布的文章集合
     * @return list
     */
    @Override
    public Result findCurrentUserArticle() {
        Long uid = ThreadLocalUtil.getUid();
        List<Article> articles = articleMapper.selectList(new LambdaQueryWrapper<Article>()
                .eq(Article::getUid, uid)
                .ne(Article::getState, 3));
        return Result.OK(articles);
    }

    /**
     * 逻辑删除到回收站
     * @param id 文章id
     * @return
     */
    @Override
    public Result deleteArticleToRecycle(Long id) {
        Long uid = ThreadLocalUtil.getUid();
        int delete = articleMapper.update(new LambdaUpdateWrapper<Article>()
                .eq(Article::getId, id)
                .eq(Article::getUid, uid)
                .set(Article::getState, 3));
        if (delete == 0){
            return Result.FILE("删除失败！");
        }
        return Result.OK(null);
    }

    /**
     * 查看回收站
     * @return
     */
    @Override
    public Result showRecycle() {
        Long uid = ThreadLocalUtil.getUid();
        List<Article> articles = articleMapper.selectList(new LambdaQueryWrapper<Article>()
                .eq(Article::getUid, uid)
                .eq(Article::getState, 3));
        return Result.OK(articles);
    }

    /**
     * 真正删除
     * @param id
     * @return
     */
    @Override
    public Result deleteArticle(Long id) {
        Long uid = ThreadLocalUtil.getUid();
        int delete = articleMapper.delete(new LambdaQueryWrapper<Article>()
                .eq(Article::getId,id)
                .eq(Article::getUid,uid)
                .eq(Article::getState,3));
        if (delete == 0){
            return Result.FILE("删除失败！");
        }
        return Result.OK(null);
    }
}
